﻿using System;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.Xml.Serialization;
using System.IO;
using System.Web.Script.Serialization;
using System.Collections.Specialized;


namespace Derrick.Web
{
    public class WebSocketClient : Client
    {

        protected WebSocketMessage _messageReceived = new WebSocketMessage();
        protected string _secWebSocketKey;

        public string WebSocketKey
        {
            get { return _secWebSocketKey; }
        }

        public WebSocketClient(TcpClient c, Server s, AuthConfig a, int id)
            : base(c, s, a, id)
        {

        }

        public override void ParseRequestContent()
        {
            if (_traceSwitch == null)
            {
                _traceSwitch = new TraceSwitch("TraceLevelSwitch", "Comet Tracing");
            }

            Trace.WriteLineIf(_traceSwitch.TraceInfo, "Inside WebSocketClient.ParseRequestContent()...");

            bool isHandshake = false;

            if (String.IsNullOrEmpty(request.Body))
            {
                Trace.WriteLineIf(_traceSwitch.TraceVerbose, "No content in the body of the request.  Should be initiating handshake...");
                isHandshake = true;
            }

            try
            {

                if (!isHandshake)
                {
                    MemoryStream mem = new MemoryStream();
                    mem.Write(System.Text.Encoding.ASCII.GetBytes(request.Body), 0, request.Body.Length);
                    mem.Seek(0, 0);
                }

                #region Extract headers re web socket protocol

                if (request.Headers.ContainsValue("GET /chat HTTP/1.1"))
                {
                    _messageReceived.Method = "GET /chat HTTP/1.1";
                }
                if (request.Headers.ContainsKey("Host"))
                {
                    _messageReceived.Host = request.Headers["Host"];
                }
                if (request.Headers.ContainsKey("Upgrade"))
                {
                    _messageReceived.Upgrade = request.Headers["Upgrade"];
                }
                if (request.Headers.ContainsKey("Connection"))
                {
                    _messageReceived.Connection = request.Headers["Connection"];
                }
                if (request.Headers.ContainsKey("Sec-WebSocket-Key"))
                {
                    _messageReceived.SecWebSocketKey = request.Headers["Sec-WebSocket-Key"];
                    _secWebSocketKey = _messageReceived.SecWebSocketKey;
                }
                if (request.Headers.ContainsKey("Origin"))
                {
                    _messageReceived.Origin = request.Headers["Origin"];
                }
                if (request.Headers.ContainsKey("Sec-WebSocket-Protocol"))
                {
                    _messageReceived.SecWebSocketProtocol = request.Headers["Sec-WebSocket-Protocol"];
                }
                if (request.Headers.ContainsKey("Sec-WebSocket-Version"))
                {
                    _messageReceived.SecWebSocketVersion = request.Headers["Sec-WebSocket-Version"];
                }
                if (request.Headers.ContainsKey("Sec-WebSocket-Extensions"))
                {
                    _messageReceived.SecWebSocketExtensions = request.Headers["Sec-WebSocket-Extensions"];
                }

                #endregion Extract headers re web socket protocol

                #region Deal with Web Socket handshake

                if (isHandshake)
                {
                    Trace.WriteLineIf(_traceSwitch.TraceVerbose, "WebSocketClient::ParseRequestContent().  Detected as handshake request.  Processing...", "Web Socket Server");

                    bool upgradeCorrect = false;
                    bool connectionCorrect = false;
                    bool secProtocolCorrect = false;

                    if (!String.IsNullOrEmpty(_messageReceived.Upgrade))
                    {
                        if (_messageReceived.Upgrade.ToLower().Contains("websocket"))
                        {
                            upgradeCorrect = true;
                            Trace.WriteLineIf(_traceSwitch.TraceVerbose, "WebSocketClient::ParseRequestContent().  Header Upgrade:websocket detected.", "Web Socket Server");
                        }
                    }

                    if (!String.IsNullOrEmpty(_messageReceived.Connection))
                    {
                        if (_messageReceived.Connection.ToLower().Contains("upgrade"))
                        {
                            connectionCorrect = true;
                            Trace.WriteLineIf(_traceSwitch.TraceVerbose, "WebSocketClient::ParseRequestContent().  Header Connection:upgrade detected.", "Web Socket Server");
                        }
                    }

                    if (!String.IsNullOrEmpty(_messageReceived.SecWebSocketProtocol))
                    {
                        if (_messageReceived.SecWebSocketProtocol.ToLower().Contains("chat") &&
                            _messageReceived.SecWebSocketProtocol.ToLower().Contains("superchat"))
                        {
                            secProtocolCorrect = true;
                            Trace.WriteLineIf(_traceSwitch.TraceVerbose, "WebSocketClient::ParseRequestContent().  Header SecWebSocketProtocol: chat/superchat detected.", "Web Socket Server");
                        }
                    }

                    if (upgradeCorrect && connectionCorrect)
                    {
                        Trace.WriteLineIf(_traceSwitch.TraceVerbose, "WebSocketClient::ParseRequestContent()...Sending handshake response.", "Web Socket Server");
                        SendHandshakeResponse();
                    }

                }

                #endregion Deal with Web Socket handshake


            }
            catch (Exception ex)
            {
                Trace.WriteLineIf(_traceSwitch.TraceVerbose, "Client.ParseRequestContent() general exception: " + ex.ToString());
            }

        }

        public override void SendResponseThread(Object context)
        {
            SendMessageEventArgs args = context as SendMessageEventArgs;
            SendResponse(args);
        }

        public override void SendResponse(SendMessageEventArgs args)
        {
            WebSocketResponse response = WebSocketResponse.GetWebSocketResponse(args.Message);
            response.SendMessage(args.Message, this);
        }

        public void SendHandshakeResponse()
        {
            WebSocketResponse response = new WebSocketResponse();
            response.SendHandshakeResponse(stream, this);
        }


    }
}
